/**
 * client module
 * 
 * @author strlst <e11907086@student.tuwien.ac.at>
 * @date 2020-01-01
 * @brief TODO: write
 * @brief contains implementations of the main entry point and auxiliary
 * methods of the client header
 */

#include "client.h"

void die(char *message, char *program, int exit_code) {
    fprintf(stderr, message, program, strerror(errno));
    exit(exit_code);
}

void usage() {
    fprintf(stderr, "usage: client [-c] [-p PORT] [ -o FILE | -d DIR ] URL\n");
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
    uint16_t opt_port = 80;
    char *opt_file = NULL;
    char *opt_dir = NULL;
    char *opt_url = NULL;
    int opt_compress = 0;

    char c;
    int count = 1;

    /* parse arguments */
    while ((c = getopt(argc, argv, "cp:o:d:")) != -1) {
        switch (c) {
            case 'p':
                opt_port = strtol(optarg, NULL, 0);
                if (opt_port == 0)
                    usage();
                count += 2;
                break;
            case 'o':
                opt_file = optarg;
                count += 2;
                break;
            case 'd':
                opt_dir = optarg;
                count += 2;
                break;
            case 'c':
                opt_compress = 1;
                count += 1;
                break;
            /* unsupported arugments */
            case '?':
                usage();
                break;
            /* should never happen */
            default:
                assert(0);
        }
    }

    /* there can't be no arguments */
    /* there can only be 1 extra argument, the URL */
    /* the extra argument must be supplied */
    if (argc <= 1 || argc > count + 1 || optind == argc)
        usage();

    /* only one of both opts can be set */
    if (opt_file != NULL && opt_dir != NULL)
        usage();

    opt_url = argv[optind];

    /* parse url components */
    url req_url = parse(argv[0], opt_url);

    /* some bassic assertions */
    assert(req_url.webserver != NULL);
    assert(req_url.path != NULL);
    assert(req_url.file != NULL);
    assert(strcmp(req_url.webserver, "") != 0);
    assert(strcmp(req_url.file, "") != 0);

    /* debugging stuff */
    if (DEBUG)
        print_url(req_url);

    /* set up desired output stream */
    /* the reason this happens before the http exchange is */
    /* to prevent a possibly unnecessary request */
    FILE *file;
    /* in this case the user specified a file */
    if (opt_file != NULL) {
        /* open specified filename for writing */
        file = fopen(opt_file, "w");
    /* in this case the user specified a directory in which to create */
    /* a file in */
    } else if (opt_dir != NULL) {
        /* check for a trailing slash and store either 0 or 1 */
        int trailing_slash = opt_dir[strlen(opt_dir) - 1] == '/';
        char *filepath;
        long int opt_dir_len = strlen(opt_dir);
        /* in case of no trailing slash, we need one more character */
        filepath = malloc(opt_dir_len + strlen(req_url.file) + 1 + !trailing_slash);
        /* check if allocation succeeded */
        if (filepath == NULL)
            die("%s: failed allocating filepath\n", argv[0], EXIT_FAILURE);
        /* distinguish these two critical cases */
        if (trailing_slash) {
            /* copy opt dir and file into target string */
            strcpy(filepath, opt_dir);
            strcpy(filepath + opt_dir_len, req_url.file);
            printf("%s\n", filepath);
        } else {
            /* copy opt dir, middle '/' and file into target string */
            strcpy(filepath, opt_dir);
            filepath[opt_dir_len] = '/';
            strcpy(filepath + opt_dir_len + 1, req_url.file);
            printf("%s\n", filepath);
        }
        file = fopen(filepath, "w");
        free(filepath);
    /* just use stdout otherwise */
    } else {
        file = stdout;
    }

    /* check whether file was set appropriately */
    if (file == NULL)
        die("%s: error opening file for writing: %s\n", argv[0], EXIT_FAILURE);

    /* establish connection */
    request req;
    //req.http_version = "1.1";
    req.http_version = malloc(4);
    if (req.http_version == NULL)
        die("%s: could not allocate req.http_version: %s\n", argv[0], EXIT_FAILURE);
    strcpy(req.http_version, "1.1");
    /* GET is an enum member defined in "url.h" */
    req.req_port = opt_port;
    req.req_method = GET;
    req.req_url = req_url;
    req.compressed = opt_compress;

    /* debugging stuff */
    if (DEBUG)
        print_request(req);

    /* send http request with output streamed to stdout */
    send_request(argv[0], req, file);

    /* cleanup structures */
    destroy_request(req);
    destroy_url(req_url);

    return EXIT_SUCCESS;
}